﻿Shader "Unlit/Cartoon(NormalChange)"
{
    Properties{

        _MainTex ("Main Texture", 2D) = "white"{}
        _BumpTex ("Normal Texture", 2D) = "white"{}
        _RampTex ("Ramp Texture", 2D) = "white"{}

        _BaseColor ("Base Color", Color) = (1.0,1.0,1.0,1.0)

        _OutlineWidth ("Outline Width", Range(0, 0.05)) = 0.05
        _OutlineColor ("Outline Color", Color) = (1.0,1.0,1.0,1.0)

        _SpecularScale ("Specular Scale", Range(1, 20)) = 15
        _BumpScale ("Bump Scale", Range(-5, 5)) = 1 
        _SpecularStep ("Specular Step", Range(0, 5)) = 1 
    }

    SubShader
    {
        pass
        {
            Cull front
            ZWrite off

            Tags
            {
                "LightMode" = "LightweightForward"
                "RenderType"="TransParent"
                "RenderPipeline"="UniversalRenderPipeline"
                "Queue" = "3000"
            }

            HLSLPROGRAM

                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
                #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"

                CBUFFER_START(UnityPerMaterial)
                    half4 _OutlineColor;
                    half _OutlineWidth;
                CBUFFER_END

                #pragma vertex Vertex
                #pragma fragment Pixel

                struct vertexInput{

                    float3 vertex:POSITION;
                    float3 normal:NORMAL;    
                };

                struct vertexOutput{
                    
                    float4 pos:SV_POSITION;
                };

                vertexOutput Vertex(vertexInput v)
                {
                    vertexOutput o;
                    v.vertex.xyz += normalize(v.normal) * _OutlineWidth;
                    o.pos = TransformObjectToHClip(v.vertex.xyz);
                    return o;
                }

                half4 Pixel(vertexOutput i) : SV_TARGET
                {
                    return half4(_OutlineColor.rgb, 1);
                }

            ENDHLSL
        }

        pass
        {
            //Cull Back
            
            Tags
            {
                "RenderType"="Opaqua"
                "RenderPipeline"="UniversalRenderPipeline"
            }

            HLSLPROGRAM

                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
                #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"

                TEXTURE2D(_MainTex);
                SAMPLER(sampler_MainTex);

                TEXTURE2D(_BumpTex);
                SAMPLER(sampler_BumpTex);

                TEXTURE2D(_RampTex);
                SAMPLER(sampler_RampTex);

                CBUFFER_START(UnityPerMaterial)
                    float4 _MainTex_ST, _BumpTex_ST;
                    half4 _BaseColor, _OutlineColor;
                    half _OutlineWidth;
                    half _SpecularScale;
                    half _BumpScale;
                    half _SpecularStep;
                CBUFFER_END

                #pragma vertex Vertex
                #pragma fragment Pixel

                struct vertexInput{

                    float3 vertex:POSITION;
                    float3 normal:NORMAL;    
                    float2 uv_MainTex:TEXCOORD0;
                    float2 uv_BumpTex:TEXCOORD1;
                    float4 tangent:TANGENT;
                };

                struct vertexOutput{
                    
                    float4 pos:SV_POSITION;
                    float2 uv_MainTex:TEXCOORD0;
                    float2 uv_BumpTex:TEXCOORD1;
                    float4 TW1:TEXCOORD2;
                    float4 TW2:TEXCOORD3;
                    float4 TW3:TEXCOORD4;
                };

                vertexOutput Vertex(vertexInput v)
                {
                    vertexOutput o;
                    o.pos = TransformObjectToHClip(v.vertex.xyz);
                    float3 worldSelfNormal = TransformObjectToWorldNormal(v.normal);
                    float3 worldTangent = TransformObjectToWorldDir(v.tangent.xyz);
                    float3 worldBinormal = cross(worldSelfNormal, worldTangent) * v.tangent.w;

                    float3 worldPos = TransformObjectToWorld(v.vertex.xyz);

                    o.TW1 = float4(worldTangent.x, worldBinormal.x, worldSelfNormal.x, worldPos.x);
                    o.TW2 = float4(worldTangent.y, worldBinormal.y, worldSelfNormal.y, worldPos.y);
                    o.TW3 = float4(worldTangent.z, worldBinormal.z, worldSelfNormal.z, worldPos.z);

                    o.uv_MainTex = TRANSFORM_TEX(v.uv_MainTex, _MainTex);
                    o.uv_BumpTex = TRANSFORM_TEX(v.uv_MainTex, _BumpTex);
                    return o;
                }

                half4 Pixel(vertexOutput i) : SV_TARGET
                {
                    /* 提取在顶点着色器中的数据 */
                    float3x3 TangentToWorld = float3x3(i.TW1.xyz, i.TW2.xyz, i.TW3.xyz);
                    float3 worldPos = half3(i.TW1.w, i.TW2.w, i.TW3.w);
                    
                    /* 先计算最终的世界法线 */
                    float4 normalTex = SAMPLE_TEXTURE2D(_BumpTex, sampler_BumpTex, i.uv_BumpTex);//对法线纹理采样
                    float3 bump = UnpackNormal(normalTex);//解包，也就是将法线从0,1重新映射回-1,1
                    bump.xy *= _BumpScale;
                    bump.z = sqrt(1.0 - saturate(bump.xy * bump.xy));
                    //这个z的计算是因为法线仅存储x和y信息，而z可以由x^2 + y^2 + z^2 = 1反推出来。（法线是单位矢量）
                    bump = normalize(mul(TangentToWorld, bump)); //将切线空间中的法线转换到世界空间中

                    /*计算纹理颜色*/
                    Light light = GetMainLight();
                    half3 albedo = _BaseColor.xyz * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv_MainTex).xyz * light.color.rgb;

                    /*计算漫反射光照*/
                    half3 lightDir = normalize(light.direction);

                    //计算半兰伯特漫反射系数，亮化处理，将结果从[-1,1]映射到[0,1]，以便作为渐变纹理的采样uv
                    half diff = dot(bump, lightDir);
                    diff = (diff * 0.5 + 0.5);
                    float4 rampCol = SAMPLE_TEXTURE2D(_RampTex, sampler_RampTex, float2(diff, diff));
                    
                    half3 diffuse = albedo * saturate(dot(lightDir, bump)) * rampCol.rgb;

                    /*计算Blinn-Phong高光*/
                    half3 viewDir = normalize(_WorldSpaceCameraPos.xyz - worldPos);
                    half3 reflectDir = normalize(reflect(-lightDir, bump));
                    half3 specular = pow(saturate(dot(viewDir, reflectDir)), _SpecularScale);
                    specular = step(1 - specular, _SpecularStep);
                    return half4(diffuse + specular, 1);
                }

            ENDHLSL
        }
    }
}
